package software.lib.service;

import com.sun.istack.internal.NotNull;
import software.lib.util.functional.*;

/**
 * Created by Wang on 2017/5/27.
 */
public class Distance {
    /**
     * L1 范数 曼哈顿距离
     * @param vector1 向量1
     * @param vector2 向量2
     * @return 距离
     */
    public static Double L1(Object[] vector1,Object[] vector2){
        //TODO 暂默认各项均为数值，后期应加入String等其它相似度计算
        double dist=0.0;
        for (int i = 0; i < vector1.length; i++) {
            dist += Math.abs(transferToDouble(vector1[i]) - transferToDouble(vector2[i]));
        }
        return dist;
    }

    /**
     * L1 范数 欧几里得距离
     * @param vector1 向量1
     * @param vector2 向量2
     * @return 距离
     */
    public static Double L2(Object[] vector1,Object[] vector2){
        //TODO 暂默认各项均为数值，后期应加入String等其它相似度计算
        double dist=0.0;
        for (int i = 0; i < vector1.length; i++) {
            double subVal = (transferToDouble(vector1[i]) - transferToDouble(vector2[i]));
            dist += subVal*subVal;
        }
        return Math.sqrt(dist);
    }

    /**
     * 闵可夫斯基距离 LN 范数  可使用TriFunction.adaptFirst 适配为一个BiFunction
     * @param n 范数的阶
     * @param vector1 向量1
     * @param vector2 向量2
     * @return 距离
     * @see TriFunction
     */
    public static Double LN(double n,Object[] vector1,Object[] vector2){
        //TODO 暂默认各项均为数值，后期应加入String等其它相似度计算
        double dist=0.0;
        for (int i = 0; i < vector1.length; i++) {
            double subVal = Math.abs(transferToDouble(vector1[i]) - transferToDouble(vector2[i]));
            dist += Math.pow(subVal,n);
        }
        return Math.pow(dist,-n);
    }

    /**
     * L∞   切比雪夫距离
     * @param vector1 向量1
     * @param vector2 向量2
     * @return 距离
     */
    public static Double chebyshev(Object[] vector1,Object[] vector2){
        //TODO 暂默认各项均为数值，后期应加入String等其它相似度计算
        double dist=0.0;
        for (int i = 0; i < vector1.length; i++) {
            dist = Math.max(Math.abs(transferToDouble(vector1[i]) - transferToDouble(vector2[i])),dist);
        }
        return dist;
    }

    public static double transferToDouble(@NotNull Object o){
        if(o instanceof Number){
            return ((Number)o).doubleValue();
        }
        return 0;
    }
}
